home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 6 / Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso / 039a / mawk.zip / FILES.C < prev    next >
C/C++ Source or Header  |  1991-04-07  |  7KB  |  300 lines

  1.  
  2. /********************************************
  3. files.c
  4. copyright 1991, Michael D. Brennan
  5.  
  6. This is a source file for mawk, an implementation of
  7. the Awk programming language as defined in
  8. Aho, Kernighan and Weinberger, The AWK Programming Language,
  9. Addison-Wesley, 1988.
  10.  
  11. See the accompaning file, LIMITATIONS, for restrictions
  12. regarding modification and redistribution of this
  13. program in source or binary form.
  14. ********************************************/
  15.  
  16. /*$Log:    files.c,v $
  17.  * Revision 2.1  91/04/08  08:23:05  brennan
  18.  * VERSION 0.97
  19.  * 
  20. */
  21.  
  22. /* files.c */
  23.  
  24. #include "mawk.h"
  25. #include "files.h"
  26. #include "memory.h"
  27. #include <stdio.h>
  28. #include "fin.h"
  29.  
  30. #if  ! DOS
  31. #include <fcntl.h>
  32. #endif
  33.  
  34. /* We store dynamically created files on a linked linear
  35.    list with move to the front (big surprise)  */
  36.  
  37. typedef struct file {
  38. struct file *link ;
  39. STRING  *name ;
  40. short type ;
  41. #if   ! DOS
  42. int pid ;  /* we need to wait() when we close an out pipe */
  43. #endif
  44. PTR   ptr ;  /* FIN*   or  FILE*   */
  45. }  FILE_NODE ;
  46.  
  47. static FILE_NODE *file_list ;
  48.  
  49. PTR  file_find( sval, type )
  50.   STRING *sval ;
  51.   int type ;
  52. { register FILE_NODE *p = file_list ;
  53.   FILE_NODE *q = (FILE_NODE *) 0 ;
  54.   char *name = sval->str ;
  55.  
  56.   while (1)
  57.   {
  58.     if ( !p )   /* open a new one */
  59.     {
  60.       p = (FILE_NODE*) zmalloc(sizeof(FILE_NODE)) ;
  61.       switch( p->type = type )
  62.       {
  63.         case  F_TRUNC :
  64.             if ( !(p->ptr = (PTR) fopen(name, "w")) )
  65.                 goto out_failure ;
  66.             break ;
  67.  
  68.         case  F_APPEND :
  69.             if ( !(p->ptr = (PTR) fopen(name, "a")) )
  70.                 goto out_failure ;
  71.             break ;
  72.  
  73.         case  F_IN  :
  74.             if ( !(p->ptr = (PTR) FINopen(name, 0)) )
  75.             { zfree(p, sizeof(FILE_NODE)) ; return (PTR) 0 ; }
  76.             break ;
  77.  
  78.         case  PIPE_OUT :
  79.         case  PIPE_IN :
  80. #if   DOS
  81.             rt_error("pipes not supported under MsDOS") ;
  82. #else
  83.             if ( !(p->ptr = get_pipe(name, type, &p->pid)) )
  84.                 if ( type == PIPE_OUT ) goto out_failure ;
  85.                 else
  86.                 { zfree(p, sizeof(FILE_NODE) ) ;
  87.                   return (PTR) 0 ;
  88.                 }
  89. #endif
  90.             break ;
  91.  
  92. #ifdef  DEBUG
  93.         default :
  94.             bozo("bad file type") ;
  95. #endif
  96.       }
  97.       /* successful open */
  98.       p->name = sval ;
  99.       sval->ref_cnt++ ;
  100.       break ;
  101.     }
  102.  
  103.     if ( strcmp(name, p->name->str) == 0 )
  104.     { 
  105.       if ( p->type != type )  goto type_failure ;
  106.       if ( !q )  /*at front of list */
  107.           return  p->ptr ;
  108.       /* delete from list for move to front */
  109.       q->link = p->link ;
  110.       break ;
  111.     }
  112.     q = p ; p = p->link ;
  113.   }
  114.  
  115.   /* put p at the front of the list */
  116.   p->link = file_list ;
  117.   return  (PTR) (file_list = p)->ptr ;
  118.  
  119. out_failure:
  120.   errmsg(errno, "cannot open \"%s\" for output", name) ;
  121.   mawk_exit(1) ;
  122.  
  123. type_failure :
  124.   rt_error("use of file \"%s\"\n\tis inconsistent with previous use",
  125.            name) ;
  126. }
  127.  
  128.  
  129. /* close a file and delete it's node from the file_list */
  130.  
  131. int  file_close( sval )
  132.   STRING *sval ;
  133. { register FILE_NODE *p = file_list ;
  134.   FILE_NODE *q = (FILE_NODE *) 0 ; /* trails p */
  135.   char *name = sval->str ;
  136.  
  137.   while ( p )
  138.         if ( strcmp(name,p->name->str) == 0 ) /* found */
  139.         { 
  140.           switch( p->type )
  141.           {
  142.             case  F_TRUNC :
  143.             case  F_APPEND :    
  144.                 (void) fclose((FILE *) p->ptr) ;
  145.                 break ;
  146.  
  147.             case  PIPE_OUT :
  148.                 (void) fclose((FILE *) p->ptr) ;
  149. #if  ! DOS
  150.                 (void) wait_for(p->pid) ;
  151. #endif
  152.                 break ;
  153.  
  154.             case F_IN  :
  155.             case PIPE_IN :
  156.                 FINclose((FIN *) p->ptr) ;
  157.                 break ;
  158.           }
  159.  
  160.           free_STRING(p->name) ;
  161.           if ( q )  q->link = p->link ;
  162.           else  file_list = p->link ;
  163.  
  164.           zfree(p, sizeof(FILE_NODE)) ;
  165.           return 0 ;
  166.         }
  167.         else { q = p ; p = p->link ; }
  168.  
  169.   /* its not on the list */
  170.   return -1 ;
  171. }
  172.  
  173. /* When we exit, we need to close and wait for all output pipes */
  174.  
  175. #if   !DOS
  176. void close_out_pipes()
  177. { register FILE_NODE *p = file_list ;
  178.  
  179.   while ( p )
  180.   { if ( p->type == PIPE_OUT )
  181.     { (void) fclose((FILE *) p->ptr) ;  (void) wait_for(p->pid) ; }
  182.     p = p->link ;
  183.   }
  184. }
  185. #endif
  186.  
  187.  
  188. char *shell ;
  189.  
  190. #if  !  DOS
  191. PTR get_pipe( name, type, pid_ptr)
  192.   char *name ;
  193.   int type ;
  194.   int *pid_ptr ;
  195. { int the_pipe[2], local_fd, remote_fd ;
  196.  
  197.   if ( ! shell ) shell = (shell = getenv("SHELL")) ? shell :"/bin/sh" ;
  198.   
  199.   if ( pipe(the_pipe) == -1 )  return (PTR) 0 ;
  200.   local_fd = the_pipe[type == PIPE_OUT] ;
  201.   remote_fd = the_pipe[type == PIPE_IN ] ;
  202.  
  203.   switch( *pid_ptr = fork() )
  204.   { case -1 :  
  205.       (void) close(local_fd) ;
  206.       (void) close(remote_fd) ;
  207.       return (PTR) 0 ;
  208.  
  209.     case  0 :
  210.         (void) close(local_fd) ;
  211.         (void) close(type == PIPE_IN) ;
  212.         (void) dup( remote_fd ) ;
  213.         (void) close( remote_fd ) ;
  214.         (void) execl(shell, shell, "-c", name, (char *) 0 ) ;
  215.         errmsg(errno, "failed to exec %s -c %s" , shell, name) ;
  216.     fflush(stderr) ;
  217.         _exit(128) ;
  218.  
  219.     default :
  220.         (void) close(remote_fd) ;
  221.         /* we could deadlock if future child inherit the local fd ,
  222.            set close on exec flag */
  223.         (void) fcntl(local_fd, F_SETFD, 1) ;
  224.         break ;
  225.   }
  226.  
  227.   return  type == PIPE_IN ? (PTR) FINdopen(local_fd, 0) : 
  228.                             (PTR)  fdopen(local_fd, "w")  ;
  229. }
  230.   
  231.  
  232.  
  233. /*------------ children ------------------*/
  234.  
  235. /* we need to wait for children at the end of output pipes to
  236.    complete so we know any files they have created are complete */
  237.  
  238. /* dead children are kept on this list */
  239.  
  240. static struct child {
  241. int pid ;
  242. int exit_status ;
  243. struct child *link ;
  244. }  *child_list ;
  245.  
  246. static  void  add_to_child_list(pid, exit_status)
  247.   int pid, exit_status ;
  248. { register struct child *p = 
  249.           (struct child *) zmalloc(sizeof(struct child)) ;
  250.  
  251.   p->pid = pid ; p->exit_status = exit_status ;
  252.   p->link = child_list ; child_list = p ;
  253. }
  254.  
  255. static struct child *remove_from_child_list(pid)
  256.   int pid ;
  257. { register struct child *p = child_list ;
  258.   struct child *q = (struct child *) 0 ;
  259.  
  260.   while ( p )
  261.     if ( p->pid == pid )
  262.     {
  263.         if ( q ) q->link = p->link ;
  264.         else child_list = p->link ;
  265.         break ;
  266.     }
  267.     else { q = p ; p = p->link ; }
  268.  
  269.   return p ;  /* null return if not in the list */
  270. }
  271.     
  272.  
  273. /* wait for a specific child to complete and return its 
  274.    exit status */
  275.  
  276. int wait_for(pid)
  277.   int pid ;
  278. { int exit_status ;
  279.   struct child *p ;
  280.   int id ;
  281.  
  282.   /* see if an earlier wait() caught our child */
  283.   if ( p = remove_from_child_list(pid) ) 
  284.   { exit_status = p->exit_status ;
  285.     zfree(p, sizeof(struct child)) ;
  286.   }
  287.   else /* need to really wait */
  288.     while ( (id = wait(&exit_status)) != pid )
  289.         if ( id == -1 ) /* can't happen */  bozo("wait_for") ;
  290.         else
  291.         { /* we got the exit status of another child
  292.              put it on the child list and try again */
  293.           add_to_child_list(id, exit_status ) ;
  294.         }
  295.  
  296.   return exit_status ;
  297. }
  298.         
  299. #endif
  300.